<template>
    <div class="key-mapper mb-6">
        <!-- 钢琴窗口 -->
        <div class="mt-4 beautiful-scrollbar" style="overflow-x: scroll">
            <Piano :octave="[0, 9]" width="4200px" height="200px" v-slot="{ value, color }" @click="setNow">
                <div class="piano-sign" :class="color + '-sign'">
                    <div>{{ value }}</div>
                    <v-icon
                        v-if="note === value || value in rule"
                        size="1.1em"
                        :color="note === value ? 'primary' : undefined"
                    >
                        {{ note === value ? "mdi-star" : "mdi-check-circle" }}
                    </v-icon>
                </div>
            </Piano>
        </div>

        <div class="mt-4" style="display: flex; flex-direction: row; align-items: center; justify-content: center">
            <!-- 按键输入框 -->
            <div style="width: 0; flex-grow: 1">
                <key-input v-model="shortcut" :label="`${sign} - ${note}`" immediate />
            </div>

            <!-- 保存按钮 -->
            <div class="ml-4">
                <v-btn style="background-color: transparent" icon @click="save">
                    <v-icon>mdi-content-save-outline</v-icon>
                    <v-tooltip activator="parent" location="top">保存设置</v-tooltip>
                </v-btn>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, watch } from "vue";
import { injectMessageState } from "@/lib/view";
import { Shortcut, KeyCode } from "@/lib/keyboard";
import type { KeyMapper, KeyMapperValue } from "@/lib/mapper";
import useMapperStore from "@/store/mapper";
import Piano from "@/components/public/keyboard/Piano.vue";
import KeyInput from "@/components/public/keyboard/KeyInput.vue";

const mapper = useMapperStore();

const rule = ref<KeyMapper["rule"]>({});

const note = ref(60);
const sign = ref("C5");
const shortcut = ref(Shortcut.state());

updateState();

// 全局消息状态
const messageState = injectMessageState();

/**
 * 监听 mapper 变化
 */
watch(() => mapper.name, updateState);

/**
 * 监听设置变化
 */
watch(shortcut, (shortcut) => {
    if (shortcut.keyCode === KeyCode.Unidentified) {
        delete rule.value[note.value.toString()];
    } else {
        const res: KeyMapperValue[] = [];

        if (shortcut.ctrl) {
            res.push(KeyCode[KeyCode.ControlLeft] as any);
        }

        if (shortcut.shift) {
            res.push(KeyCode[KeyCode.ShiftLeft] as any);
        }

        if (shortcut.alt) {
            res.push(KeyCode[KeyCode.AltLeft] as any);
        }

        if (shortcut.meta) {
            res.push(KeyCode[KeyCode.SuperLeft] as any);
        }

        res.push(KeyCode[shortcut.keyCode] as any);

        // 添加到 rule 中
        rule.value[note.value.toString()] = res;
    }
});

/**
 * 更新状态
 */
function updateState() {
    // 1. 例行设置
    note.value = 60;
    sign.value = "C5";

    // 2. rule 设置
    if (mapper.now.name === "KeyMapper") {
        rule.value = mapper.now.rule;
    } else {
        console.warn(`不合法的 KeyMapper 配置文件`);
        rule.value = {};
    }

    // 3. 检查并设置 KeyCode
    setKeyCode(rule.value[note.value]?.map((e) => KeyCode[e]) ?? []);
}

/**
 * 设置当前索引
 * @param index 当前索引
 * @param signStr 当前音符字
 */
function setNow(index: number, signStr: string) {
    if (note.value === index) {
        return;
    }

    note.value = index;
    sign.value = signStr;
    setKeyCode(rule.value[note.value]?.map((e) => KeyCode[e]) ?? []);
}

/**
 * 设置 KeyCode
 * @param charCode VK的字符码
 */
function setKeyCode(keyCodes: KeyCode[]) {
    // shortcut.value = Shortcut.state();
    // 会导致更新不及时，输入框内容没有变化
    shortcut.value.alt = false;
    shortcut.value.ctrl = false;
    shortcut.value.shift = false;
    shortcut.value.meta = false;

    if (keyCodes.length === 0) {
        shortcut.value.keyCode = KeyCode.Unidentified;
    } else if (keyCodes.length === 1) {
        shortcut.value.keyCode = keyCodes[0];
    } else {
        for (let i = 0; i < keyCodes.length - 1; ++i) {
            switch (keyCodes[i]) {
                case KeyCode.ControlLeft:
                case KeyCode.ControlRight:
                    shortcut.value.ctrl = true;
                    break;
                case KeyCode.ShiftLeft:
                case KeyCode.ShiftRight:
                    shortcut.value.shift = true;
                    break;
                case KeyCode.AltLeft:
                case KeyCode.AltRight:
                    shortcut.value.alt = true;
                    break;
                case KeyCode.SuperLeft:
                case KeyCode.SuperRight:
                    shortcut.value.meta = true;
            }
        }
        shortcut.value.keyCode = keyCodes[keyCodes.length - 1];
    }
}

/**
 * 保存设置
 */
async function save() {
    // 保存设置
    const res = await mapper.setMapper({
        name: "KeyMapper",
        rule: rule.value,
    });

    // 显示消息
    messageState.visible = true;
    if (res) {
        messageState.text = `键盘映射器 “${mapper.name}” 保存成功`;
    } else {
        messageState.text = `键盘映射器 “${mapper.name}” 保存失败`;
    }
}
</script>

<style scoped lang="scss">
.key-mapper {
    .piano-sign {
        display: flex;
        align-items: center;
        gap: 2px;
        user-select: none;
    }

    .white-sign {
        font-size: 20px;
        color: #333;
        margin-bottom: 4px;
        flex-direction: column-reverse;
    }

    .black-sign {
        font-size: 18px;
        color: #ccc;
        margin-top: 4px;
        flex-direction: column;
    }
}
</style>
